package com.acme.bankapp.apps;

import java.io.BufferedReader;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.HashSet;
import java.util.Set;

import com.acme.bankapp.domain.*;
import com.acme.bankapp.services.DataWorker;
import com.acme.bankapp.services.ReportService;
import com.sun.java_cup.internal.runtime.virtual_parse_stack;

public class ServerApplication {

    private final int port;


    private BankService bankService;

    public ServerApplication(int port) {
        this.port = port;
    }

    public void start() {
        start("bank");
    }

    public void start(String bankSerialization) {
        bankService = new BankService();
        System.out.println("Server started");

        while (true) {
            try (ServerSocket serverSocket = new ServerSocket(port);
                 Socket clientSocket = serverSocket.accept();
                 PrintWriter out = new PrintWriter(
                         clientSocket.getOutputStream(), true);
                 BufferedReader in = new BufferedReader(
                         new InputStreamReader(clientSocket.getInputStream()))) {

                String inputLine;
                String outputLine;

                out.println(BankApplication.INITIAL_MESSAGE);

                while (true) {


                    while ((inputLine = in.readLine()) != null) {
//                        System.out.println("Client: " + inputLine);
                        if (inputLine.equals(BankApplication.END_SESSION_MESSAGE)) {
                            System.out.println("client disconnected, waiting for new one");
                            return;
                        }
                        outputLine = processMessage(inputLine);
//                        System.out.println(outputLine);
                        out.println(outputLine);
                    }
                }
            } catch (IOException e) {
                System.err
                        .println("Exception caught when trying to listen on port "
                                + port + " or listening for a connection");
                System.out.println("client disconnected, waiting for new one");
            }
        }
    }

    private String processMessage(String message) {
        if (message.startsWith(BankApplication.ADD_CLIENT)) {
            return addClient(message.substring(BankApplication.ADD_CLIENT.length()));
        } else if (message.startsWith(BankApplication.REMOVE_CLIENT)) {
            return removeClient(message.substring(BankApplication.REMOVE_CLIENT.length()));
        }else if(message.startsWith(BankApplication.REMOVE_ALL_CLIENTS)){
               return removeAllClients();
        }else if (message.startsWith(BankApplication.GET_CLIENTS_MESSAGE_HEADER)) {
            return getClientList();
        }

        return "No such command";
    }

    private String addClient(String addClientString) {
        String[] clientInfo = addClientString.split(":");
        try {
            bankService.addClient(clientInfo[0],
                    "m".equals(clientInfo[1]) ? Gender.MALE : Gender.FEMALE);
            return "client added";
        } catch (ClientExistsException e) {
            System.err.println(e.getMessage());
            return "error happened";
        }
    }

    private String removeClient(String removeClientString) {
        Client removed = bankService.removeClient(removeClientString);
        if (removed != null) {
            return "client " + removed.getName() + " was removed";
        } else {
            return "client " + removeClientString + " wasn't found";
        }
    }

    private String removeAllClients(){
        Set<String> clientsNames = new HashSet<>();
        for(Client client : bankService.getBank().getClients()){
            clientsNames.add(client.getName());
        }
        for(String name : clientsNames){
            bankService.removeClient(name);
        }
        return "complete";
    }

    private String getClientList() {
        return new ReportService(bankService).reportBankClients().replace("\n", "\\n");
    }


}
